package com.triangulator;

import android.util.Log;


public class IntegralHVHistogram {
	private final String TAG = "IntegralHVHist";
	private int mNumPixels;
	private int mWidth;
	private int mHeight;
	
	private HVHistogram mIntegralHistogram[] = null;
	
	public IntegralHVHistogram(int image[], int image_width, int image_height) {
		mIntegralHistogram = new HVHistogram[image.length];
		
		mNumPixels = image.length;
		mWidth = image_width;
		mHeight = image_height;
		
		computeIntegralHistogram(image);
	}
	
	public void computeIntegralHistogram(int image[]) {
		int idx;
		int idx1, idx2, idx3;
		int crop[] = new int[1];
		
		for (int y=0; y<mHeight; y++) {
			for (int x=0; x<mWidth; x++) {
				idx = getPixelIndex(x,y); //y*mHeight+x;
				crop[0] = image[idx];
				
				mIntegralHistogram[idx] = new HVHistogram(crop, 1, 1);
				
				if (x==0 && y==0) {
				} else if (y==0) {
					idx1 = getPixelIndex(x-1,y); //x-1;
					mIntegralHistogram[idx].add(mIntegralHistogram[idx1], x+1, 1);
				} else if (x==0) {
					
					idx1 = getPixelIndex (x, y-1); //(y-1)*mHeight;
					mIntegralHistogram[idx].add(mIntegralHistogram[idx1], 1, y+1);

				} else {
					idx1 = getPixelIndex (x, y-1); // (y-1)*mHeight+x;
					idx2 = getPixelIndex (x-1, y); //y*mHeight+x-1;
					idx3 = getPixelIndex (x-1, y-1); //(y-1)*mHeight+x-1;
					mIntegralHistogram[idx].add(mIntegralHistogram[idx1], mIntegralHistogram[idx2], x+1, y+1);
					mIntegralHistogram[idx].subtract(mIntegralHistogram[idx3], x+1, y+1);
				}
			}
		}
	}
	
	public HVHistogram getHistogram(int x, int y, int width, int height) {
		int x1 = x+width-1;
		int y1 = y+height-1;
		int x2 = x-1;
		int y2 = y-1;
		
		int idx = getPixelIndex(x1, y1);
		
		HVHistogram h = new HVHistogram(mIntegralHistogram[idx]);
		HVHistogram h2; //, h3, h4;
		
		//Log.i("IHIST", "h: " + h.getNumPixels() + " " + x1 +  " " + y1 +  " " + x2 +  " " + y2);
		
		if (x1 >= mWidth || y1 >= mHeight) {
			Log.e("INTHISTOGRAM", "Position and height and width is incorrect.");
		}

		if (x2 < 0 && y2 < 0) {
		} else if (x2 < 0) {
			idx = getPixelIndex(x1, y2);
			h2 = new HVHistogram(mIntegralHistogram[idx]);
			h.subtract(h2, width, height);
			//Log.d(TAG, "h-h2: " + h.getNumPixels());
		} else if (y2 < 0) {
			idx = getPixelIndex(x2, y1);
			h2 = new HVHistogram(mIntegralHistogram[idx]);
			h.subtract(h2, width, height);
			//Log.d(TAG, "h-h2: " + h.getNumPixels());
		} else {
			idx = getPixelIndex(x2, y1);
			h2 = new HVHistogram(mIntegralHistogram[idx]);
			h.subtract(h2, width, height);
			//Log.d(TAG, "h-h1: " + h.getNumPixels());
			
			idx = getPixelIndex(x1, y2);
			h2 = new HVHistogram(mIntegralHistogram[idx]);
			h.subtract(h2, width, height);
			//Log.d(TAG, "h-h2: " + h.getNumPixels());
			
			idx = getPixelIndex(x2, y2);
			h2 = new HVHistogram(mIntegralHistogram[idx]);
			h.add(h2, width, height);
			//Log.d(TAG, "h+h3: " + h.getNumPixels());
		}
		
		return h;
	}
	
	public double searchHistogram(int[] match_position, HVHistogram hist, int step_x, int step_y) {
		int startx=0, endx=mWidth - hist.getWidth() + 1;
		int starty=0, endy=mHeight - hist.getHeight() + 1;

		double max = 0;
		double tmp;
		
		Log.d(TAG, startx + " " + endx + ", " + starty + " " + endy);
		
		for (int y=starty; y<endy; y+=step_y) {
			for (int x=startx; x<endx; x+=step_x) {
				tmp = getHistogram(x, y, hist.getWidth(), hist.getHeight()).histogramIntersection(hist);
				
				Log.d(TAG, x + " " + y + ": " + tmp + " vs " + max);
				Log.d(TAG, getHistogram(x, y, hist.getWidth(), hist.getHeight()).toString());
				//Log.d(TAG, hist.toString());
				
				if (tmp > max) {
					max = tmp;
					match_position[0] = x;
					match_position[1] = y;
				}
			}
		}
		
		return max;
	}
	
	public int getPixelIndex (int x, int y) {
		return y*mWidth+x;
	}
	
	public int getNumPixels() {
		return mNumPixels;
	}
	
	public int getWidth() {
		return mWidth;
	}
	
	public int getHeight() {
		return mHeight;
	}
	
	public String toString() {
		String out = new String();
		
		for (int i=0; i<mIntegralHistogram.length; i++) {
			out += mIntegralHistogram[i].toString() + "\n";
		}
		
		return out;
	}
}
